bitkeeper revision 1.108 (3e676eb6Jy0anfrUlVCNnVZnDDSlQg)
authorach61@labyrinth.cl.cam.ac.uk <ach61@labyrinth.cl.cam.ac.uk>
Thu, 6 Mar 2003 15:52:22 +0000 (15:52 +0000)
committerach61@labyrinth.cl.cam.ac.uk <ach61@labyrinth.cl.cam.ac.uk>
Thu, 6 Mar 2003 15:52:22 +0000 (15:52 +0000)
virtual block device support

16 files changed:
.rootkeys
xen/drivers/block/xen_block.c
xen/drivers/block/xen_segment.c
xen/include/hypervisor-ifs/block.h
xen/include/hypervisor-ifs/xeno-major.h [new file with mode: 0644]
xen/include/xeno/major.h
xen/include/xeno/segment.h
xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/block/Makefile
xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/block/xl_block.c
xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/block/xl_block_test.c
xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/block/xl_segment.c
xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/block/xl_segment_proc.c [new file with mode: 0644]
xenolinux-2.4.21-pre4-sparse/drivers/block/ll_rw_blk.c
xenolinux-2.4.21-pre4-sparse/include/linux/blk.h
xenolinux-2.4.21-pre4-sparse/include/linux/major.h
xenolinux-2.4.21-pre4-sparse/init/do_mounts.c

index 211a86c6d77bcca46444bc988313096ddfcade32..d4cb1b135394ea6caa061bf551a693f43718dd27 100644 (file)
--- a/.rootkeys
+++ b/.rootkeys
 3ddb79c2YTaZwOqWin9-QNgHge5RVw xen/include/hypervisor-ifs/block.h
 3ddb79c25UE59iu4JJcbRalx95mvcg xen/include/hypervisor-ifs/hypervisor-if.h
 3ddb79c2oRPrzClk3zbTkRHlpumzKA xen/include/hypervisor-ifs/network.h
+3e676eb5yHx7feWgYoqlwD2Z9WsY1w xen/include/hypervisor-ifs/xeno-major.h
 3ddb79c4qbCoOFHrv9sCGshbWzBVlQ xen/include/scsi/scsi.h
 3ddb79c4R4iVwqIIeychVQYmIH4FUg xen/include/scsi/scsi_ioctl.h
 3ddb79c4yw_mfd4Uikn3v_IOPRpa1Q xen/include/scsi/scsicam.h
 3e5a4e65iHEuC5sjFhj42XALYbLVRw xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/block/Makefile
 3e5a4e65pP5spJErBW69pJxSSdK9RA xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/block/xl_block.c
 3e5a4e65GtI9JZRAjuRdXaxt_4ohyQ xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/block/xl_block_test.c
-3e5d129aDldt6geU2-2SzBae34sQzg xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/block/xl_segment.c
+3e676eb5RXnHzSHgA1BvM0B1aIm4qg xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/block/xl_segment.c
+3e5d129aDldt6geU2-2SzBae34sQzg xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/block/xl_segment_proc.c
 3e5a4e65G3e2s0ghPMgiJ-gBTUJ0uQ xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/console/Makefile
 3e5a4e651TH-SXHoufurnWjgl5bfOA xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/console/console.c
 3e5a4e656nfFISThfbyXQOA6HN6YHw xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/dom0/Makefile
index 8e1ff1188b5b24ee394914e18a413b8b1ab08cb3..0e6a82ccc332de32d14e8d3942da6de42adc2c52 100644 (file)
@@ -41,7 +41,8 @@ static atomic_t nr_pending;
 static void io_schedule(unsigned long unused);
 static int do_block_io_op_domain(struct task_struct *p, int max_to_do);
 static void dispatch_rw_block_io(struct task_struct *p, int index);
-static void dispatch_probe_block_io(struct task_struct *p, int index);
+static void dispatch_probe_blk(struct task_struct *p, int index);
+static void dispatch_probe_seg(struct task_struct *p, int index);
 static void dispatch_debug_block_io(struct task_struct *p, int index);
 static void dispatch_create_segment(struct task_struct *p, int index);
 static void dispatch_delete_segment(struct task_struct *p, int index);
@@ -202,8 +203,12 @@ static int do_block_io_op_domain(struct task_struct* p, int max_to_do)
            dispatch_rw_block_io(p, i);
            break;
 
-       case XEN_BLOCK_PROBE:
-           dispatch_probe_block_io(p, i);
+       case XEN_BLOCK_PROBE_BLK:
+           dispatch_probe_blk(p, i);
+           break;
+
+       case XEN_BLOCK_PROBE_SEG:
+           dispatch_probe_seg(p, i);
            break;
 
        case XEN_BLOCK_DEBUG:
@@ -248,6 +253,7 @@ static void dispatch_create_segment(struct task_struct *p, int index)
 
   xvd = phys_to_virt((unsigned long)blk_ring->ring[index].req.buffer);    
   result = xen_segment_create(xvd);
+
   make_response(p, blk_ring->ring[index].req.id, 
                XEN_BLOCK_SEG_CREATE, result); 
   return;
@@ -258,7 +264,7 @@ static void dispatch_delete_segment(struct task_struct *p, int index)
     DPRINTK("dispatch_delete_segment: unimplemented\n"); 
 }
 
-static void dispatch_probe_block_io(struct task_struct *p, int index)
+static void dispatch_probe_blk(struct task_struct *p, int index)
 {
     extern void ide_probe_devices(xen_disk_info_t *xdi, int *count, 
                                  drive_t xdrives[]);
@@ -269,7 +275,19 @@ static void dispatch_probe_block_io(struct task_struct *p, int index)
     ide_probe_devices(xdi, &num_xdrives, xdrives);
     /* scsi_probe_devices(xdi, &num_xdrives, xdrives); */          /* future */
 
-    make_response(p, blk_ring->ring[index].req.id, XEN_BLOCK_PROBE, 0);
+    make_response(p, blk_ring->ring[index].req.id, XEN_BLOCK_PROBE_BLK, 0);
+}
+
+static void dispatch_probe_seg(struct task_struct *p, int index)
+{
+    extern void xen_segment_probe(xen_disk_info_t *xdi, int *count);
+    blk_ring_t *blk_ring = p->blk_ring_base;
+    xen_disk_info_t *xdi;
+
+    xdi = phys_to_virt((unsigned long)blk_ring->ring[index].req.buffer);    
+    xen_segment_probe(xdi, &num_xdrives);
+
+    make_response(p, blk_ring->ring[index].req.id, XEN_BLOCK_PROBE_SEG, 0);
 }
 
 static void dispatch_rw_block_io(struct task_struct *p, int index)
@@ -279,8 +297,11 @@ static void dispatch_rw_block_io(struct task_struct *p, int index)
     struct buffer_head *bh;
     int operation;
     unsigned short size;
+    unsigned long  block_number = 0L;
+    unsigned long  sector_number = 0L;
     unsigned long buffer, pfn;
     struct pfn_info *page;
+    int xen_device, phys_device = 0;
 
     operation = (blk_ring->ring[index].req.operation == XEN_BLOCK_WRITE) ? 
         WRITE : READ;
@@ -345,11 +366,50 @@ static void dispatch_rw_block_io(struct task_struct *p, int index)
 
     /* set just the important bits of the buffer header */
     memset (bh, 0, sizeof (struct buffer_head));
+
+    /* map from virtual xeno devices to physical ide & scsi devices */
+    xen_device = blk_ring->ring[index].req.device;
+    if (IS_XHD_MAJOR(xen_device))
+    {
+      if (xen_device == XHDA_MAJOR)             phys_device = MKDEV(IDE0_MAJOR, 0);
+      else if (xen_device == XHDB_MAJOR) phys_device = MKDEV(IDE1_MAJOR, 0);
+      else if (xen_device == XHDC_MAJOR) phys_device = MKDEV(IDE2_MAJOR, 0);
+      else if (xen_device == XHDD_MAJOR) phys_device = MKDEV(IDE3_MAJOR, 0);
+      else
+      {
+       printk (KERN_ALERT "dispatch_rw_block_io: unknown device %d\n",
+               xen_device);
+       BUG();
+      }
+
+      block_number = blk_ring->ring[index].req.block_number;
+      sector_number = blk_ring->ring[index].req.sector_number;
+    }
+    else if (IS_VHD_MAJOR(xen_device))
+    {
+      int s;
+      if (s = xen_segment_map_request(&phys_device, &block_number, 
+                                     &sector_number,
+                                     p, operation, xen_device,
+                                     blk_ring->ring[index].req.block_number,
+                                     blk_ring->ring[index].req.sector_number))
+      {
+       printk ("dispatch_rw_block_io: xen_segment_map_request status: %d\n",
+               s);
+       goto bad_descriptor;
+      }
+    }
+    else
+    {
+      printk (KERN_ALERT "dispatch_rw_block_io: unknown device %d\n",
+             xen_device);
+      BUG();
+    }
     
-    bh->b_blocknr       = blk_ring->ring[index].req.block_number;
+    bh->b_blocknr       = block_number;
     bh->b_size          = size;
-    bh->b_dev           = blk_ring->ring[index].req.device; 
-    bh->b_rsector       = blk_ring->ring[index].req.sector_number;
+    bh->b_dev           = phys_device;
+    bh->b_rsector       = sector_number;
     bh->b_data          = phys_to_virt(buffer);
     bh->b_count.counter = 1;
     bh->b_end_io        = end_block_io_op;
@@ -373,6 +433,7 @@ static void dispatch_rw_block_io(struct task_struct *p, int index)
     return;
 
  bad_descriptor:
+    printk (KERN_ALERT "dispatch rw blockio bad descriptor\n");
     make_response(p, blk_ring->ring[index].req.id, XEN_BLOCK_READ, 1);
     return;
 } 
@@ -407,8 +468,23 @@ static void make_response(struct task_struct *p, void *id,
 
 static void dump_blockq(u_char key, void *dev_id, struct pt_regs *regs) 
 {
-    printk("Dumping block queue stats: nr_pending = %d\n",
-           atomic_read(&nr_pending));
+  struct task_struct *p;
+  blk_ring_t *blk_ring ;
+
+  printk("Dumping block queue stats: nr_pending = %d\n",
+        atomic_read(&nr_pending));
+
+  p = current->next_task;
+  do
+  {
+    printk (KERN_ALERT "Domain: %d\n", p->domain);
+    blk_ring = p->blk_ring_base;
+
+    printk("  req_prod:%d, resp_prod:%d, req_cons:%d\n",
+          blk_ring->req_prod, blk_ring->resp_prod, p->blk_req_cons);
+
+    p = p->next_task;
+  } while (p != current);
 }
 
 /* Start-of-day initialisation for a new domain. */
@@ -419,7 +495,11 @@ void init_blkdev_info(struct task_struct *p)
     clear_page(p->blk_ring_base);
     SHARE_PFN_WITH_DOMAIN(virt_to_page(p->blk_ring_base), p->domain);
     p->blkdev_list.next = NULL;
+
+    memset(p->segment_list, 0, sizeof(p->segment_list));
     p->segment_count = 0;
+
+    xen_refresh_segment_list(p);      /* get any previously created segments */
 }
 
 /* End-of-day teardown for a domain. XXX Outstanding requests? */
index 1105afe1c72dbde0d30388db1365f02c47bdd146..c326138c30d40a64712a8118315636c16ef4b039 100644 (file)
 #include <xeno/slab.h>
 #include <xeno/segment.h>
 #include <xeno/sched.h>
+#include <xeno/blkdev.h>
 #include <xeno/keyhandler.h>
+#include <asm/current.h>
+#include <asm/domain_page.h>
 #include <hypervisor-ifs/block.h>
+#include <hypervisor-ifs/xeno-major.h>
 
 int     num_xdrives;
 drive_t xdrives[XEN_MAX_DISK_COUNT];
 
 segment_t xsegments[XEN_MAX_SEGMENTS];
 
+/*
+ * xen_segment_map_request
+ *
+ * xen_device must be a valid device.
+ */
+
+int xen_segment_map_request(int *phys_device,                         /* out */
+                           unsigned long *block_number,              /* out */
+                           unsigned long *sector_number,             /* out */
+                           struct task_struct *domain,
+                           int operation,
+                           int xen_device,
+                           int xen_block_number,
+                           int xen_sector_number)
+{
+  segment_t *seg;
+  int segment_number;                   /* segment number within this domain */
+  int sum; 
+  int loop;
+
+  segment_number = xen_device - XLSEG_MAJOR;
+  seg = domain->segment_list[segment_number];
+
+  if (seg == NULL)
+  {
+    return 1;                                       /* oops.  no vhd exists! */
+  }
+
+  /* check domain permissions */
+  if (seg->domain != domain->domain)
+  {
+    return 2;                                  /* domain doesn't own segment */
+  }
+
+  /* check rw access */
+  if ((operation == WRITE && seg->mode != XEN_SEGMENT_RW) ||
+      (operation == READ  && seg->mode == XEN_SEGMENT_UNUSED))
+  {
+    return 3;                                            /* access violation */
+  }
+
+  /* find extent, check size */
+  sum = 0; 
+  loop = 0;
+  while (loop < seg->num_extents && sum <= xen_block_number)
+  {
+    sum += seg->extents[loop++].size;
+  }
+  sum -= seg->extents[--loop].size;                                /* rewind */
+
+  if (sum + seg->extents[loop].size <= xen_block_number)
+  {
+    return 4;                   /* tried to read past the end of the segment */
+  }
+  *block_number = xen_block_number - sum + seg->extents[loop].offset;
+  *sector_number = xen_sector_number - sum + seg->extents[loop].offset;;
+
+  /* get physical device from xdrives */
+  *phys_device = MKDEV(xdrives[seg->extents[loop].disk].major, 0);
+
+  /*
+  printk ("%d %lx %lx %lx %lx :  %lx %lx %lx %lx\n",
+         operation,
+         *block_number, xen_block_number, sum, seg->extents[loop].offset,
+         *sector_number, xen_sector_number, sum, seg->extents[loop].offset
+         );
+  */
+
+  return 0;
+}
+
+/*
+ * xen_segment_probe
+ *
+ * return a list of segments to the guestos
+ */
+void xen_segment_probe (xen_disk_info_t *raw_xdi, int *count)
+{
+  int loop, i;
+  xen_disk_info_t *xdi = map_domain_mem(virt_to_phys(raw_xdi));
+
+  for (loop = 0; loop < XEN_MAX_SEGMENTS; loop++ )
+  {
+    if (xsegments[loop].mode != XEN_SEGMENT_UNUSED)
+    {
+      xdi->disks[xdi->count].type = XEN_DISK_VIRTUAL;
+      for (i = 0; i < xsegments[loop].num_extents; i++)
+      {
+       xdi->disks[xdi->count].capacity += xsegments[loop].extents[i].size;
+      }
+      xdi->count++;
+    }
+  }
+
+  unmap_domain_mem(xdi);
+  return;
+}
+
 /*
  * xen_refresh_segment_list
  *
@@ -59,7 +161,8 @@ int xen_segment_create(xv_disk_t *xvd_in)
   }
   if (idx == XEN_MAX_SEGMENTS)
   {
-    printk (KERN_ALERT "error: xen_segment_create unable to find free slot\n");
+    printk (KERN_ALERT "xen_segment_create: unable to find free slot\n");
+    unmap_domain_mem(xvd);
     return 1;
   }
 
@@ -76,8 +179,16 @@ int xen_segment_create(xv_disk_t *xvd_in)
     xsegments[idx].extents[loop].disk = xvd->extents[loop].disk;
     xsegments[idx].extents[loop].offset = xvd->extents[loop].offset;
     xsegments[idx].extents[loop].size = xvd->extents[loop].size;
+    if (xsegments[idx].extents[loop].size == 0) 
+    {
+      printk (KERN_ALERT "xen_segment_create: extent %d is zero length\n",
+             loop);
+      unmap_domain_mem(xvd);
+      return 1;
+    }
   }
 
+  unmap_domain_mem(xvd);
   return 0;
 }
 
@@ -96,6 +207,7 @@ int xen_segment_delete(struct task_struct *p, xv_disk_t *xvd)
 static void dump_segments(u_char key, void *dev_id, struct pt_regs *regs) 
 {
   int loop, i;
+  struct task_struct *p;
 
   printk (KERN_ALERT "xdrives\n");
   for (loop = 0; loop < num_xdrives; loop++)
@@ -103,7 +215,7 @@ static void dump_segments(u_char key, void *dev_id, struct pt_regs *regs)
     printk (KERN_ALERT " %2d: major: 0x%d\n", loop, xdrives[loop].major);
   }
   
-  printk (KERN_ALERT "segments\n");
+  printk (KERN_ALERT "segment list\n");
   for (loop = 0; loop < XEN_MAX_SEGMENTS; loop++)
   {
     if (xsegments[loop].mode != XEN_SEGMENT_UNUSED)
@@ -122,6 +234,22 @@ static void dump_segments(u_char key, void *dev_id, struct pt_regs *regs)
       } 
     }
   }
+
+  printk (KERN_ALERT "segments by domain\n");
+  p = current->next_task;
+  do
+  {
+    printk (KERN_ALERT "  domain: %d\n", p->domain);
+    for (loop = 0; loop < p->segment_count; loop++)
+    {
+      printk (KERN_ALERT "    mode:%d domain:%d seg:%d exts:%d\n",
+             p->segment_list[loop]->mode,
+             p->segment_list[loop]->domain,
+             p->segment_list[loop]->segment_number,
+             p->segment_list[loop]->num_extents);
+    }
+    p = p->next_task;
+  } while (p != current);
 }
 
 /*
index 908f8382cce61e7d5312e0ba07b80be6a09af8ff..9459cdc17e327b9c4f9ac6fd0119991bdaafae32 100644 (file)
 #define XEN_BLOCK_WRITE 1
 #define XEN_BLOCK_READA 2                                /* currently unused */
 #define XEN_BLOCK_SPECIAL 4                              /* currently unused */
-#define XEN_BLOCK_PROBE 8      /* determine io configuration from hypervisor */
-#define XEN_BLOCK_DEBUG 16                                          /* debug */
+#define XEN_BLOCK_PROBE_BLK  8             /* get xhd config from hypervisor */
+#define XEN_BLOCK_DEBUG      16                                     /* debug */
 #define XEN_BLOCK_SEG_CREATE 32                      /* create segment (vhd) */
 #define XEN_BLOCK_SEG_DELETE 64                      /* delete segment (vhd) */
+#define XEN_BLOCK_PROBE_SEG  128           /* get vhd config from hypervisor */
 
 #define BLK_RING_SIZE        128
 #define BLK_RING_MAX_ENTRIES (BLK_RING_SIZE - 2)
@@ -70,6 +71,7 @@ typedef struct blk_ring_st
 
 #define XEN_DISK_IDE  1
 #define XEN_DISK_SCSI 2
+#define XEN_DISK_VIRTUAL 3                                            /* vhd */
 
 typedef struct xen_disk                                     /* physical disk */
 {
diff --git a/xen/include/hypervisor-ifs/xeno-major.h b/xen/include/hypervisor-ifs/xeno-major.h
new file mode 100644 (file)
index 0000000..099fe27
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * xeno_major.h
+ *
+ * shared definitions for block IO.
+ */
+
+/*
+ * this belongs in xenolinux/include/linux/major.h except that
+ * xen also needs access...
+ */
+
+
+#ifndef __XENO_MAJOR_H__
+#define __XENO_MAJOR_H__
+
+
+#define XLBLK_MAJOR    123                   /* XenoLinux Block Device: xhd */
+#define XHDA_MAJOR      123
+#define XHDB_MAJOR      124
+#define XHDC_MAJOR      125
+#define XHDD_MAJOR      126
+#define XLSEG_MAJOR     234                 /* XenoLinux Segment Device: vhd */
+#define VHDA_MAJOR      234
+#define VHDB_MAJOR      235
+#define VHDC_MAJOR      236
+#define VHDD_MAJOR      237
+
+
+/*
+ * XenoLinux Block Device Tests
+ */
+#define IS_XHD_MAJOR(M) ( (M) == XHDA_MAJOR || (M) == XHDB_MAJOR || \
+                          (M) == XHDC_MAJOR || (M) == XHDD_MAJOR ? 1 : 0)
+#define IS_VHD_MAJOR(M) ( (M) == VHDA_MAJOR || (M) == VHDB_MAJOR || \
+                          (M) == VHDC_MAJOR || (M) == VHDD_MAJOR ? 1 : 0)
+
+#endif
index b30f88baf8a609da288fb791ae14a09156f4c20c..f3a44119fc8a2470d84f37008d937eec57540cad 100644 (file)
 
 #define        UMEM_MAJOR      116     /* http://www.umem.com/ Battery Backed RAM */
 
+/* note: 123, 124, 125, 126 and 234, 235, 236, 237 are defined in xeno_major */
+#include <hypervisor-ifs/xeno-major.h>
+
 #define RTF_MAJOR      150
 #define RAW_MAJOR      162
 
index f0bf08ffbdc895da3d6c08ede8b3a6f668a6bfe6..4045da3849aff8961047cc76815c971e30300ad2 100644 (file)
@@ -6,6 +6,14 @@
 void xen_segment_initialize(void);
 void xen_refresh_segment_list (struct task_struct *p);
 int xen_segment_create(xv_disk_t *xvd);
+int xen_segment_map_request(int *phys_device,                         /* out */
+                           unsigned long *block_number,              /* out */
+                           unsigned long *sector_number,             /* out */
+                           struct task_struct *domain,
+                           int operation,
+                           int xen_device,
+                           int xen_block_number,
+                           int xen_sector_number);
 
 #define XEN_MAX_SEGMENTS 100     /* total number of segments across all doms */
 
@@ -37,8 +45,8 @@ typedef struct extent
 } extent_t;
 
 #define XEN_SEGMENT_UNUSED 0                                /* bzero default */
-#define XEN_SEGMENT_RO XEN_DISK_READ_WRITE
-#define XEN_SEGMENT_RW XEN_DISK_READ_ONLY
+#define XEN_SEGMENT_RO XEN_DISK_READ_ONLY
+#define XEN_SEGMENT_RW XEN_DISK_READ_WRITE
 
 typedef struct segment
 {
index c6d1c7dc6311ca770eddad4b148b31ef99b83d8f..594aab25b89ece5e053ab38f7f34f299e21ac6c5 100644 (file)
@@ -1,3 +1,3 @@
 O_TARGET := blk.o
-obj-y := xl_block.o xl_segment.o xl_block_test.o
+obj-y := xl_block.o xl_segment.o xl_segment_proc.o xl_block_test.o
 include $(TOPDIR)/Rules.make
index 6e7e713c866a0b34c28b8b553a1dfb868b2b438b..bc87e7eb7b16cc282f869f3d8865383f1fac0701 100644 (file)
@@ -1,7 +1,7 @@
 /******************************************************************************
  * xl_block.c
  * 
- * Xenolinux virtual block-device driver.
+ * Xenolinux virtual block-device driver (xhd).
  * 
  */
 
@@ -32,8 +32,6 @@ static int xlblk_major = XLBLK_MAJOR;
 /* Copied from linux/ide.h */
 typedef unsigned char  byte; 
 
-void xlblk_ide_register_disk(int, unsigned long);
-
 #define XLBLK_MAX 32 /* Maximum minor devices we support */
 #define XLBLK_MAJOR_NAME "xhd"
 #define IDE_PARTN_BITS 6                           /* from ide.h::PARTN_BITS */
@@ -58,15 +56,18 @@ static int xlblk_max_sectors[XLBLK_MAX];
 
 static blk_ring_t *blk_ring;
 static unsigned int resp_cons; /* Response consumer for comms ring. */
-static xen_disk_info_t xen_disk_info;
+static xen_disk_info_t xlblk_disk_info;
 atomic_t xlblk_control_count;
 
-int hypervisor_request(void *         id,
-                       int            operation,
-                       char *         buffer,
-                       unsigned long  block_number,
-                       unsigned short block_size,
-                       kdev_t         device);
+void xlblk_ide_register_disk(int, unsigned long);
+void do_xlseg_requestX (request_queue_t *rq);
+int hypervisor_request(void *          id,
+                       int             operation,
+                       char *          buffer,
+                       unsigned long   block_number,
+                       unsigned short  block_size,
+                       kdev_t          device,
+                      struct gendisk *gd);
 
 
 /* ------------------------------------------------------------------------
@@ -103,22 +104,39 @@ static int xenolinux_block_ioctl(struct inode *inode, struct file *filep,
   
     switch (command)
     {
-    case BLKGETSIZE:
+    case BLKGETSIZE:                                             /* get size */
         DPRINTK_IOCTL("   BLKGETSIZE: %x %lx\n", BLKGETSIZE, 
-                      (long) xen_disk_info.disks[0].capacity); 
-       return put_user(xen_disk_info.disks[0].capacity, 
+                      (long) xlblk_disk_info.disks[0].capacity); 
+       return put_user(xlblk_disk_info.disks[0].capacity, 
                        (unsigned long *) argument);
 
-    case BLKRRPART:
+    case BLKRRPART:                               /* re-read partition table */
         DPRINTK_IOCTL("   BLKRRPART: %x\n", BLKRRPART); 
        break;
 
-    case BLKSSZGET:
+    case BLKBSZGET:                                        /* get block size */
+        DPRINTK_IOCTL("   BLKBSZGET: %x\n", BLKBSZGET);
+       break;
+
+    case BLKBSZSET:                                        /* set block size */
+        DPRINTK_IOCTL("   BLKBSZSET: %x\n", BLKBSZSET);
+       break;
+
+    case BLKRASET:                                         /* set read-ahead */
+        DPRINTK_IOCTL("   BLKRASET: %x\n", BLKRASET);
+       break;
+
+    case BLKRAGET:                                         /* get read-ahead */
+        DPRINTK_IOCTL("   BLKRAFET: %x\n", BLKRAGET);
+       break;
+
+    case BLKSSZGET:                                       /* get sector size */
         DPRINTK_IOCTL("   BLKSSZGET: %x 0x%x\n", BLKSSZGET,
                       xlblk_hardsect_size[minor_dev]);
        return xlblk_hardsect_size[minor_dev]; 
 
     case HDIO_GETGEO:
+        /* note: these values are complete garbage */
         DPRINTK_IOCTL("   HDIO_GETGEO: %x\n", HDIO_GETGEO);
        if (!argument) return -EINVAL;
        if (put_user(0x00,  (unsigned long *) &geo->start)) return -EFAULT;
@@ -128,13 +146,13 @@ static int xenolinux_block_ioctl(struct inode *inode, struct file *filep,
        return 0;
 
     case HDIO_GETGEO_BIG: 
+        /* note: these values are complete garbage */
         DPRINTK_IOCTL("   HDIO_GETGEO_BIG: %x\n", HDIO_GETGEO_BIG);
        if (!argument) return -EINVAL;
        if (put_user(0x00,  (unsigned long *) &geo->start))  return -EFAULT;
        if (put_user(0xff,  (byte *)&geo->heads))   return -EFAULT;
        if (put_user(0x3f,  (byte *)&geo->sectors)) return -EFAULT;
        if (put_user(0x106, (unsigned int *) &geo->cylinders)) return -EFAULT;
-
        return 0;
 
     default:
@@ -163,26 +181,27 @@ static int xenolinux_block_revalidate(kdev_t dev)
  * request block io 
  * 
  * id: for guest use only.
- * operation: XEN_BLOCK_READ, XEN_BLOCK_WRITE or XEN_BLOCK_PROBE
+ * operation: XEN_BLOCK_{READ,WRITE,PROBE*,SEG*}
  * buffer: buffer to read/write into. this should be a
  *   virtual address in the guest os.
  * block_number:  block to read
  * block_size:  size of each block
- * device:  ide/hda is 768 or 0x300           should be disk#!!!
+ * device:  xhd or vhd
+ * gd: partition information if XEN_BLOCK_{READ,WRITE}
  */
-int hypervisor_request(void *         id,
-                       int            operation,
-                       char *         buffer,
-                       unsigned long  block_number,
-                       unsigned short block_size,
-                       kdev_t         device)
+int hypervisor_request(void *          id,
+                       int             operation,
+                       char *          buffer,
+                       unsigned long   block_number,
+                       unsigned short  block_size,
+                       kdev_t          device,
+                      struct gendisk *gd)
 {
     int position;
     void *buffer_ma; 
     kdev_t phys_device = (kdev_t) 0;
     unsigned long sector_number = 0;
-    struct gendisk *gd;     
-
     /*
      * Bail if there's no room in the request communication ring. This may be 
      * because we have a whole bunch of outstanding responses to process. No 
@@ -197,21 +216,38 @@ int hypervisor_request(void *         id,
     {
     case XEN_BLOCK_SEG_CREATE:
     case XEN_BLOCK_SEG_DELETE:
-    case XEN_BLOCK_PROBE:
+    case XEN_BLOCK_PROBE_BLK:
+    case XEN_BLOCK_PROBE_SEG:
        phys_device = (kdev_t) 0;
        sector_number = 0;
         break;
 
     case XEN_BLOCK_READ:
     case XEN_BLOCK_WRITE:
-       if ( MAJOR(device) != XLBLK_MAJOR ) 
+        /* only accept requests for xhd and vhd devices */
+       if (!IS_XHD_MAJOR(MAJOR(device)) && !IS_VHD_MAJOR(MAJOR(device)))
            panic("error: xl_block::hypervisor_request: "
                   "unknown device [0x%x]\n", device);
-        phys_device = MKDEV(IDE0_MAJOR, 0);
-       /* Compute real buffer location on disk */
+       phys_device = MAJOR(device);
+
+       /* Compute real buffer location on disk.
+        * note: gd will be null when we read the partition table.
+        */
        sector_number = block_number;
-       if ( (gd = (struct gendisk *)xen_disk_info.disks[0].gendisk) != NULL )
-           sector_number += gd->part[MINOR(device)&IDE_PARTN_MASK].start_sect;
+       if ( gd != NULL )
+       {
+         sector_number += gd->part[MINOR(device)&IDE_PARTN_MASK].start_sect;
+       }
+
+       /*
+       if (IS_VHD_MAJOR(MAJOR(device)))
+       {
+         printk (KERN_ALERT "%lx + %lx = %lx (%x)\n",
+                 block_number,
+                 gd->part[MINOR(device)&IDE_PARTN_MASK].start_sect,
+                 sector_number, device);
+       }
+       */
         break;
 
     default:
@@ -266,8 +302,9 @@ static void do_xlblk_request (request_queue_t *rq)
        {
             full = hypervisor_request(
                 bh, (rw == READ) ? XEN_BLOCK_READ : XEN_BLOCK_WRITE, 
-                bh->b_data, bh->b_rsector, bh->b_size, bh->b_dev);
-            
+                bh->b_data, bh->b_rsector, bh->b_size, bh->b_dev,
+               (struct gendisk *)xlblk_disk_info.disks[0].gendisk);
+
             if ( full ) goto out;
 
             queued++;
@@ -334,6 +371,7 @@ static void xlblk_response_int(int irq, void *dev_id, struct pt_regs *ptregs)
            
          case XEN_BLOCK_SEG_CREATE :
          case XEN_BLOCK_SEG_DELETE :
+         case XEN_BLOCK_PROBE_SEG :
            atomic_dec(&xlblk_control_count);
            break;
          
@@ -345,7 +383,9 @@ static void xlblk_response_int(int irq, void *dev_id, struct pt_regs *ptregs)
     resp_cons = i;
 
     /* KAF: We can push work down at this point. We have the lock. */
-    do_xlblk_request(BLK_DEFAULT_QUEUE(MAJOR_NR));
+    /* aho: okay, so this is a bit of a hack.  we'll kick every queue... */
+    do_xlblk_request(BLK_DEFAULT_QUEUE(XLBLK_MAJOR));
+    do_xlseg_requestX(BLK_DEFAULT_QUEUE(XLSEG_MAJOR));
     
     spin_unlock_irqrestore(&io_request_lock, flags);
 }
@@ -368,20 +408,23 @@ int __init xlblk_init(void)
        goto fail;
     }
 
-    memset (&xen_disk_info, 0, sizeof(xen_disk_info));
-    xen_disk_info.count = 0;
+    /* probe for disk information */
+    memset (&xlblk_disk_info, 0, sizeof(xlblk_disk_info));
+    xlblk_disk_info.count = 0;
 
-    if ( hypervisor_request(NULL, XEN_BLOCK_PROBE, (char *) &xen_disk_info,
-                            0, 0, (kdev_t) 0) )
+    if ( hypervisor_request(NULL, XEN_BLOCK_PROBE_BLK, 
+                           (char *) &xlblk_disk_info,
+                            0, 0, (kdev_t) 0, 
+                           (struct gendisk *) NULL))
         BUG();
     HYPERVISOR_block_io_op();
     while ( blk_ring->resp_prod != 1 ) barrier();
-    printk (KERN_ALERT "block device probe:\n");
-    for ( i = 0; i < xen_disk_info.count; i++ )
+    printk (KERN_ALERT "xhd block device probe:\n");
+    for ( i = 0; i < xlblk_disk_info.count; i++ )
     { 
        printk (KERN_ALERT "  %2d: type: %d, capacity: %ld\n",
-               i, xen_disk_info.disks[i].type, 
-               xen_disk_info.disks[i].capacity);
+               i, xlblk_disk_info.disks[i].type, 
+               xlblk_disk_info.disks[i].capacity);
     }
     
     SET_MODULE_OWNER(&xenolinux_block_fops);
@@ -394,7 +437,7 @@ int __init xlblk_init(void)
 
     /* initialize global arrays in drivers/block/ll_rw_block.c */
     for (i = 0; i < XLBLK_MAX; i++) {
-       xlblk_blk_size[i]      = xen_disk_info.disks[0].capacity;
+       xlblk_blk_size[i]      = xlblk_disk_info.disks[0].capacity;
        xlblk_blksize_size[i]  = 512;
        xlblk_hardsect_size[i] = 512;
        xlblk_max_sectors[i]   = 128;
@@ -415,7 +458,7 @@ int __init xlblk_init(void)
      */
     blk_queue_headactive(BLK_DEFAULT_QUEUE(xlblk_major), 0);
 
-    xlblk_ide_register_disk(0, xen_disk_info.disks[0].capacity);
+    xlblk_ide_register_disk(0, xlblk_disk_info.disks[0].capacity);
 
     printk(KERN_ALERT 
           "XenoLinux Virtual Block Device Driver installed [device: %d]\n",
@@ -461,13 +504,26 @@ void xlblk_ide_register_disk(int idx, unsigned long capacity)
 
     add_gendisk(gd);
 
-    xen_disk_info.disks[idx].gendisk = gd;
+    xlblk_disk_info.disks[idx].gendisk = gd;
 
-    /* default disk size is just a big number.  in the future, we
-       need a message to probe the devices to determine the actual size */
     register_disk(gd, MKDEV(xlblk_major, 0), 1<<IDE_PARTN_BITS,
                  &xenolinux_block_fops, capacity);
 
+    {
+      int loop = 0;
+      printk (KERN_ALERT "Partition Table: (capacity: %lx)\n", capacity);
+      for (loop = 0; loop < minors; loop++)
+      {
+       if (gd->part[loop].start_sect && gd->part[loop].nr_sects)
+       {
+         printk (KERN_ALERT 
+                 "  %2d: 0x%6lx %8ld    0x%6lx %7ld\n", loop,
+                 gd->part[loop].start_sect, gd->part[loop].start_sect,
+                 gd->part[loop].nr_sects, gd->part[loop].nr_sects);
+       }
+      }
+    }
+
     return;
 }
 
index 8d695689bab18242356c31e4b2a3be45faa0803c..b239655794d3b8feb73a7e680de7b8b23183ba86 100644 (file)
@@ -206,7 +206,8 @@ int proc_write_bdt(struct file *file, const char *buffer,
   /* submit request */
   hypervisor_request(0, meta.operation, meta.buffer, 
                     meta.block_number, meta.block_size,
-                    meta.device);
+                    meta.device, 
+                    (struct gendisk *) NULL);
   HYPERVISOR_block_io_op();
   mdelay(1000); /* should wait for a proper acknowledgement/response. */
 
index da14be14df8ff0a0214b0fd59eb33727488d2a41..0754daa9a384a1de2d065a6c948346359aa2eb4c 100644 (file)
-/*
+/******************************************************************************
  * xl_segment.c
  * 
- * XenoLinux virtual disk driver.
+ * Xenolinux virtual block-device driver (vhd).
+ * 
  */
 
-
 #include <linux/config.h>
 #include <linux/module.h>
 
-#include <linux/proc_fs.h>
-#include <linux/delay.h>
-#include <asm/uaccess.h>
-#include <asm/atomic.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+
+#include <linux/fs.h>
+#include <linux/hdreg.h>
+#include <linux/blkdev.h>
+#include <linux/major.h>
 
 #include <asm/hypervisor-ifs/block.h>
 #include <asm/hypervisor-ifs/hypervisor-if.h>
+#include <asm/io.h>
+#include <asm/atomic.h>
+#include <asm/uaccess.h>
+
+#define MAJOR_NR XLSEG_MAJOR   /* force defns in blk.h, must precede include */
+static int xlseg_major = XLSEG_MAJOR;
+#include <linux/blk.h>
+
+/* Copied from linux/ide.h */
+typedef unsigned char  byte; 
 
-static struct proc_dir_entry *vhd;
-xv_disk_t xvd;
+#define XLSEG_MAX 32 /* Maximum minor devices we support */
+#define XLSEG_MAJOR_NAME "xhd"
+
+static int xlseg_blk_size[XLSEG_MAX];
+static int xlseg_blksize_size[XLSEG_MAX];
+static int xlseg_read_ahead; 
+static int xlseg_hardsect_size[XLSEG_MAX];
+static int xlseg_max_sectors[XLSEG_MAX];
 
 extern atomic_t xlblk_control_count;                           /* xl_block.c */
 
-/******************************************************************/
+int hypervisor_request(void *          id,
+                       int             operation,
+                       char *          buffer,
+                       unsigned long   block_number,
+                       unsigned short  block_size,
+                       kdev_t          device,
+                      struct gendisk *gd);
+void xlseg_register_disk(int idx, unsigned long capacity);
+
+#if 0
+#define DPRINTK(_f, _a...) printk ( KERN_ALERT _f , ## _a )
+#define DPRINTK_IOCTL(_f, _a...) printk ( KERN_ALERT _f , ## _a )
+#else
+#define DPRINTK(_f, _a...) ((void)0)
+#define DPRINTK_IOCTL(_f, _a...) ((void)0)
+#endif
+
+static xen_disk_info_t xlseg_disk_info;
 
-static int proc_read_vhd(char *page, char **start, off_t off,
-                        int count, int *eof, void *data)
+/* ------------------------------------------------------------------------
+ */
+
+static int xenolinux_segment_open(struct inode *inode, struct file *filep)
 {
-  return 0;
+    DPRINTK("xenolinux_segment_release\n");
+    return 0;
 }
 
-#define isdelim(c) \
-  (c==' '||c==','||c=='\n'||c=='\r'||c=='\t'||c==':'||c=='('||c==')' ? 1 : 0)
+static int xenolinux_segment_release(struct inode *inode, struct file *filep)
+{
+    DPRINTK("xenolinux_segment_release\n");
+    return 0;
+}
 
-char *get_string(char *string)                          /* a bit like strtok */
+static int xenolinux_segment_ioctl(struct inode *inode, struct file *filep,
+                                  unsigned command, unsigned long argument)
 {
-  static char *temp;
-  int loop = 0;
+    int minor_dev;
+    struct hd_geometry *geo = (struct hd_geometry *)argument;
+    struct gendisk *gd = (struct gendisk *)xlseg_disk_info.disks[0].gendisk;
+
+    DPRINTK("xenolinux_segment_ioctl\n"); 
+
+    /* check permissions */
+    if (!capable(CAP_SYS_ADMIN)) return -EPERM;
+    if (!inode)                  return -EINVAL;
+    minor_dev = MINOR(inode->i_rdev);
+    if (minor_dev >= XLSEG_MAX)  return -ENODEV;
+    
+    DPRINTK_IOCTL("command: 0x%x, argument: 0x%lx, minor: 0x%x\n",
+                  command, (long) argument, minor_dev); 
+  
+    switch (command)
+    {
+      case BLKGETSIZE:
+       if (gd != NULL)
+       {
+         printk(KERN_ALERT "minordev: %d\n", minor_dev);
+         printk(KERN_ALERT "[0] start: %lx\n", gd->part[0].start_sect);
+         printk(KERN_ALERT "[0] count: %lx\n", gd->part[0].nr_sects);
+         printk(KERN_ALERT "[1] start: %lx\n", gd->part[1].start_sect);
+         printk(KERN_ALERT "[1] count: %lx\n", gd->part[1].nr_sects);
+         printk(KERN_ALERT "[2] start: %lx\n", gd->part[2].start_sect);
+         printk(KERN_ALERT "[2] count: %lx\n", gd->part[2].nr_sects);
+         
+         DPRINTK_IOCTL("   BLKGETSIZE gd: %x %lx\n", BLKGETSIZE, 
+                       gd->part[minor_dev].nr_sects);
+         return put_user(gd->part[minor_dev].nr_sects,
+                         (unsigned long *)argument);
+       }
+       else
+       {
+         DPRINTK_IOCTL("   BLKGETSIZE disk: %x %lx\n", BLKGETSIZE, 
+                       xlseg_disk_info.disks[0].capacity);
+         return put_user(xlseg_disk_info.disks[0].capacity,
+                         (unsigned long *) argument);
+       }
+                     
+      case BLKRRPART:
+        DPRINTK_IOCTL("   BLKRRPART: \n"); 
+       /* we don't have re-validate drive yet...  so you need to reboot! */
+       break;
+
+      case BLKSSZGET:
+        DPRINTK_IOCTL("   BLKSSZGET: %d\n",
+                     xlseg_hardsect_size[minor_dev]);
+       return xlseg_hardsect_size[minor_dev]; 
+
+      case HDIO_GETGEO:
+        /* note: these values are complete garbage */
+        DPRINTK_IOCTL("   HDIO_GETGEO: \n");
+       if (!argument) return -EINVAL;
+       if (put_user(0x00,  (unsigned long *) &geo->start)) return -EFAULT;
+       if (put_user(0xff,  (byte *)&geo->heads)) return -EFAULT;
+       if (put_user(0x3f,  (byte *)&geo->sectors)) return -EFAULT;
+       if (put_user(0x106, (unsigned short *)&geo->cylinders)) return -EFAULT;
+       return 0;
+
+      case HDIO_GETGEO_BIG: 
+        /* note: these values are complete garbage */
+        DPRINTK_IOCTL("   HDIO_GETGEO_BIG\n");
+       if (!argument) return -EINVAL;
+       if (put_user(0x00,  (unsigned long *) &geo->start))  return -EFAULT;
+       if (put_user(0xff,  (byte *)&geo->heads))   return -EFAULT;
+       if (put_user(0x3f,  (byte *)&geo->sectors)) return -EFAULT;
+       if (put_user(0x106, (unsigned int *) &geo->cylinders)) return -EFAULT;
+       return 0;
+
+      default:
+        DPRINTK_IOCTL("   eh? unknown ioctl\n");
+       break;
+    }
+    
+    return 0;
+}
 
-  if (string != NULL)  
-    temp = string;
-  else
-    string = temp;
+static int xenolinux_segment_check(kdev_t dev)
+{
+    DPRINTK("xenolinux_segment_check\n");
+    return 0;
+}
 
- try_again:
+static int xenolinux_segment_revalidate(kdev_t dev)
+{
+    DPRINTK("xenolinux_segment_revalidate\n"); 
+    return 0;
+}
 
-  while (!isdelim(string[loop]))
-  {
-    if (string[loop] == '\0')
-      return NULL;
-    loop++;
-  }
+void do_xlseg_requestX (request_queue_t *rq)
+{
+  /* this is a bit dumb.  do_xlseg_request is defined in blk.h
+     and this is thus static. but we have cooperative
+     device drivers... */
+  do_xlseg_request(rq);
+}
 
-  string[loop] = '\0'; 
-  temp = (string + loop + 1);
+/*
+ * do_xlseg_request
+ * read a block; request is in a request queue
+ */
+static void do_xlseg_request (request_queue_t *rq)
+{
+    struct request *req;
+    struct buffer_head *bh;
+    int rw, nsect, full, queued = 0;
+    
+    /*     DPRINTK("do_xlseg_request for '%s'\n", DEVICE_NAME); */
 
-  if (loop == 0)
-  {
-    string = temp;
-    goto try_again;
-  }
+    while ( !rq->plugged && !QUEUE_EMPTY )
+    {
+       if ( (req = CURRENT) == NULL ) goto out;
+               
+        DPRINTK("do_xlseg_request %p: cmd %i, sec %lx, (%li/%li) bh:%p\n",
+                req, req->cmd, req->sector,
+                req->current_nr_sectors, req->nr_sectors, req->bh);
+
+        rw = req->cmd;
+        if ( rw == READA ) rw = READ;
+        if ((rw != READ) && (rw != WRITE))
+            panic("XenoLinux Virtual Segment Device: bad cmd: %d\n", rw);
+
+       req->errors = 0;
+
+        bh = req->bh;
+        while ( bh != NULL )
+       {
+            full = hypervisor_request(
+                bh, (rw == READ) ? XEN_BLOCK_READ : XEN_BLOCK_WRITE, 
+                bh->b_data, bh->b_rsector, bh->b_size, bh->b_dev,
+               (struct gendisk *)xlseg_disk_info.disks[0].gendisk);
+            
+            if ( full ) 
+           {
+             goto out;
+           }
+
+            queued++;
+
+            /* Dequeue the buffer head from the request. */
+            nsect = bh->b_size >> 9;
+            req->bh = bh->b_reqnext;
+            bh->b_reqnext = NULL;
+            bh = req->bh;
+            
+            if ( bh != NULL )
+            {
+                /* There's another buffer head to do. Update the request. */
+                req->hard_sector += nsect;
+                req->hard_nr_sectors -= nsect;
+                req->sector = req->hard_sector;
+                req->nr_sectors = req->hard_nr_sectors;
+                req->current_nr_sectors = bh->b_size >> 9;
+                req->buffer = bh->b_data;
+            }
+            else
+            {
+                /* That was the last buffer head. Finalise the request. */
+                if ( end_that_request_first(req, 1, "XenSeg") ) BUG();
+                blkdev_dequeue_request(req);
+                end_that_request_last(req);
+            }
+        }
+    }
 
-  return string;
+ out:
+    if ( queued != 0 ) HYPERVISOR_block_io_op();
 }
 
 
-#define isdigit(c) (c >= '0' && c <= '9' ? 1 : 0)
-unsigned long to_number(char *string)                                /* atoi */
+static struct block_device_operations xenolinux_segment_fops = 
 {
-  unsigned long value = 0;
+    open:               xenolinux_segment_open,
+    release:            xenolinux_segment_release,
+    ioctl:              xenolinux_segment_ioctl,
+    check_media_change: xenolinux_segment_check,
+    revalidate:         xenolinux_segment_revalidate,
+};
 
-  if (string == NULL) return 0;
 
-  while (!isdigit(*string) && *string != '\0') string++;
+int __init xlseg_init(void)
+{
+    int i, result;
+    int counter;
 
-  while (isdigit(*string))
-  {
-    value = value * 10 + (*string - '0');
-    string++;
-  }
+    /* probe for disk information */
+    memset (&xlseg_disk_info, 0, sizeof(xlseg_disk_info));
+    xlseg_disk_info.count = 0;
 
-  return value;
-}
 
-static int proc_write_vhd(struct file *file, const char *buffer,
-                         unsigned long count, void *data)
-{
-  char *local = kmalloc((count + 1) * sizeof(char), GFP_KERNEL);
-  char *string;
-  int loop;
-  int counter;
-  xv_disk_t xvd;
-
-  memset (&xvd, 0, sizeof(xvd));
-
-  if (copy_from_user(local, buffer, count))
-  {
-    return -EFAULT;
-  }
-  local[count] = '\0';
-
-  string = get_string(local);                             /* look for Domain */
-  if (string == NULL)                                        /* empty string */
-  {
-    return count;
-  }
-  if (*string != 'd' && *string != 'D')
-  {
-    printk (KERN_ALERT 
-           "error: domain specifier missing [%s]. should be \"domain\".\n",
-           string);
-    return count;
-  }
-
-  string = get_string(NULL);                                /* domain number */
-  if (string == NULL)
-  {
-    printk (KERN_ALERT "error: domain number missing\n");
-    return count;
-  }
-  xvd.domain = (int) to_number(string);
-
-  string = get_string(NULL);
-  if (string && (strcmp(string, "RO") == 0 || strcmp(string, "ro") == 0))
-  {
-    xvd.mode = XEN_DISK_READ_ONLY;
-  }
-  else if (string && (strcmp(string, "RW") == 0 || strcmp(string, "rw") == 0))
-  {
-    xvd.mode = XEN_DISK_READ_ONLY;
-  }
-  else
-  {
-    printk (KERN_ALERT 
-           "error: bad mode [%s]. should be \"rw\" or \"ro\".\n",
-           string);
-    return count;
-  }
-
-  string = get_string(NULL);                             /* look for Segment */
-  if (string == NULL || (*string != 's' && *string != 'S'))
-  {
-    printk (KERN_ALERT 
-           "error: segment specifier missing [%s]. should be \"segment\".\n",
-           string);
-    return count;
-  }
-
-  string = get_string(NULL);                               /* segment number */
-  if (string == NULL)
-  {
-    printk (KERN_ALERT "error: segment number missing\n");
-    return count;
-  }
-  xvd.segment = (int) to_number(string);
-
-  string = get_string(NULL);                             /* look for Extents */
-  if (string == NULL || (*string != 'e' && *string != 'E'))
-  {
-    printk (KERN_ALERT 
-           "error: extents specifier missing [%s]. should be \"extents\".\n",
-           string);
-    return count;
-  }
-
-  string = get_string(NULL);                            /* number of extents */
-  if (string == NULL)
-  {
-    printk (KERN_ALERT "error: number of extents missing\n");
-    return count;
-  }
-  xvd.ext_count = (int) to_number(string);
-
-  /* ignore parenthesis */
-
-  for (loop = 0; loop < xvd.ext_count; loop++)
-  {
-    string = get_string(NULL);                              /* look for Disk */
-    if (string == NULL || (*string != 'd' && *string != 'D'))
     {
-      printk (KERN_ALERT 
-             "hmm, extent disk specifier missing [%s]. should be \"disk\".\n",
-             string);
-      return count;
+      /* get lock xlblk_control_lock     */
+      counter = atomic_read(&xlblk_control_count);
+      atomic_inc(&xlblk_control_count);
+      /* release lock xlblk_control_lock */
     }
-    string = get_string(NULL);                                /* disk number */
-    if (string == NULL)
-    {
-      printk (KERN_ALERT "error: disk number missing\n");
-      return count;
+    if ( hypervisor_request(NULL, XEN_BLOCK_PROBE_SEG, 
+                           (char *) &xlseg_disk_info,
+                            0, 0, (kdev_t) 0,
+                           (struct gendisk *)NULL) )
+        BUG();
+    HYPERVISOR_block_io_op();
+    while (atomic_read(&xlblk_control_count) != counter) barrier();
+
+    printk (KERN_ALERT "vhd block device probe:\n");
+    for ( i = 0; i < xlseg_disk_info.count; i++ )
+    { 
+       printk (KERN_ALERT "  %2d: type: %d, capacity: %ld\n",
+               i, xlseg_disk_info.disks[i].type, 
+               xlseg_disk_info.disks[i].capacity);
     }
-    xvd.extents[loop].disk = (int) to_number(string);
 
-    string = get_string(NULL);                            /* look for Offset */
-    if (string == NULL || (*string != 'o' && *string != 'O'))
-    {
-      printk (KERN_ALERT 
-             "error: disk offset missing [%s]. should be \"offset\".\n",
-           string);
-      return count;
+    SET_MODULE_OWNER(&xenolinux_segment_fops);
+    result = register_blkdev(xlseg_major, "segment", &xenolinux_segment_fops);
+    if (result < 0) {
+       printk (KERN_ALERT "xenolinux segment: can't get major %d\n",
+               xlseg_major);
+       return result;
     }
-    string = get_string(NULL);                                     /* offset */
-    if (string == NULL)
-    {
-      printk (KERN_ALERT "error: offset missing\n");
-      return count;
-    }
-    xvd.extents[loop].offset =  to_number(string);
 
-    string = get_string(NULL);                              /* look for Size */
-    if (string == NULL || (*string != 's' && *string != 'S'))
-    {
-      printk (KERN_ALERT 
-             "error: extent size missing [%s]. should be \"size\".\n",
-           string);
-      return count;
-    }
-    string = get_string(NULL);                                       /* size */
-    if (string == NULL)
+    /* initialize global arrays in drivers/block/ll_rw_block.c */
+    for (i = 0; i < XLSEG_MAX; i++) 
     {
-      printk (KERN_ALERT "error: extent size missing\n");
-      return count;
+      xlseg_blk_size[i]      = xlseg_disk_info.disks[0].capacity ;
+      xlseg_blksize_size[i]  = 512;
+      xlseg_hardsect_size[i] = 512;
+      xlseg_max_sectors[i]   = 128;
     }
-    xvd.extents[loop].size =  to_number(string);
-  }
+    xlseg_read_ahead  = 8; 
 
-  {
-    /* get lock xlblk_control_lock     */
-    counter = atomic_read(&xlblk_control_count);
-    atomic_inc(&xlblk_control_count);
-    /* release lock xlblk_control_lock */
-  }
+    blk_size[xlseg_major]      = xlseg_blk_size;
+    blksize_size[xlseg_major]  = xlseg_blksize_size;
+    hardsect_size[xlseg_major] = xlseg_hardsect_size;
+    read_ahead[xlseg_major]    = xlseg_read_ahead; 
+    max_sectors[xlseg_major]   = xlseg_max_sectors;
 
-  hypervisor_request (NULL, XEN_BLOCK_SEG_CREATE, (char *)&xvd,
-                     0, 0, (kdev_t) 0);
-  HYPERVISOR_block_io_op();
+    blk_init_queue(BLK_DEFAULT_QUEUE(xlseg_major), do_xlseg_request);
 
-  while (atomic_read(&xlblk_control_count) != counter) barrier();
+    /*
+     * Turn off barking 'headactive' mode. We dequeue buffer heads as
+     * soon as we pass them down to Xen.
+     */
+    blk_queue_headactive(BLK_DEFAULT_QUEUE(xlseg_major), 0);
 
-  /* while ( blk_ring->resp_prod != 1 ) barrier(); */
+    xlseg_register_disk(0, xlseg_disk_info.disks[0].capacity);
 
-  /*  mdelay(1000); */
-
-  return count;
+    printk(KERN_ALERT 
+          "XenoLinux Virtual Segment Device Driver installed [device: %d]\n",
+          xlseg_major);
+    return 0;
 }
 
-/******************************************************************/
-
-int __init xlseg_init(void)
+void xlseg_register_disk(int idx, unsigned long capacity)
 {
-  vhd = create_proc_entry("xeno/dom0/vhd", 0644, NULL);
-  if (vhd == NULL)
-  {
-    panic ("xlseg_init: unable to create vhd proc entry\n");
-  }
-  vhd->data       = NULL;
-  vhd->read_proc  = proc_read_vhd;
-  vhd->write_proc = proc_write_vhd;
-  vhd->owner      = THIS_MODULE;
-
-  memset(&xvd, 0, sizeof(xvd));
-
-  printk(KERN_ALERT "XenoLinux Virtual Disk Device Driver installed\n");
-  return 0;
+    int units;
+    int minors;
+    struct gendisk *gd;
+
+    /* plagarized from ide-probe.c::init_gendisk */
+    
+    units = 2; /* from ide.h::MAX_DRIVES */
+
+#define IDE_PARTN_BITS 6                           /* from ide.h::PARTN_BITS */
+
+    minors    = units * (1<<IDE_PARTN_BITS);
+    gd        = kmalloc (sizeof(struct gendisk), GFP_KERNEL);
+    gd->sizes = kmalloc (minors * sizeof(int), GFP_KERNEL);
+    gd->part  = kmalloc (minors * sizeof(struct hd_struct), GFP_KERNEL);
+    memset(gd->part, 0, minors * sizeof(struct hd_struct));
+    
+    gd->major        = xlseg_major;  
+    gd->major_name   = XLSEG_MAJOR_NAME;
+    gd->minor_shift  = IDE_PARTN_BITS; 
+    gd->max_p       = 1<<IDE_PARTN_BITS;
+    gd->nr_real             = units;           
+    gd->real_devices = NULL;          
+    gd->next        = NULL;            
+    gd->fops         = &xenolinux_segment_fops;
+    gd->de_arr       = kmalloc (sizeof *gd->de_arr * units, GFP_KERNEL);
+    gd->flags       = kmalloc (sizeof *gd->flags * units, GFP_KERNEL);
+
+    if (gd->de_arr)  
+       memset (gd->de_arr, 0, sizeof *gd->de_arr * units);
+
+    if (gd->flags) 
+       memset (gd->flags, 0, sizeof *gd->flags * units);
+
+    add_gendisk(gd);
+
+    xlseg_disk_info.disks[idx].gendisk = gd;
+
+    register_disk(gd, MKDEV(xlseg_major, 0), 1<<IDE_PARTN_BITS,
+                 &xenolinux_segment_fops, capacity);
+
+    {
+      int loop = 0;
+      printk (KERN_ALERT "Partition Table: (capacity: %lx)\n", capacity);
+      for (loop = 0; loop < minors; loop++)
+      {
+       if (gd->part[loop].start_sect && gd->part[loop].nr_sects)
+       {
+         printk (KERN_ALERT 
+                 "  %2d: 0x%6lx %8ld    0x%6lx %7ld\n", loop,
+                 gd->part[loop].start_sect, gd->part[loop].start_sect,
+                 gd->part[loop].nr_sects, gd->part[loop].nr_sects);
+       }
+      }
+    }
+
+    return;
 }
 
+
 static void __exit xlseg_cleanup(void)
 {
-  printk(KERN_ALERT "XenoLinux Virtual Disk Device Driver uninstalled\n");
+    /* CHANGE FOR MULTIQUEUE */
+    blk_cleanup_queue(BLK_DEFAULT_QUEUE(xlseg_major));
+
+    /* clean up global arrays */
+    read_ahead[xlseg_major] = 0;
+
+    if (blk_size[xlseg_major]) 
+       kfree(blk_size[xlseg_major]);
+    blk_size[xlseg_major] = NULL;
+
+    if (blksize_size[xlseg_major]) 
+       kfree(blksize_size[xlseg_major]);
+    blksize_size[xlseg_major] = NULL;
+
+    if (hardsect_size[xlseg_major]) 
+       kfree(hardsect_size[xlseg_major]);
+    hardsect_size[xlseg_major] = NULL;
+    
+    /* XXX: free each gendisk */
+    if (unregister_blkdev(xlseg_major, "block"))
+       printk(KERN_ALERT
+              "XenoLinux Virtual Segment Device Driver uninstalled w/ errs\n");
+    else
+       printk(KERN_ALERT 
+              "XenoLinux Virtual Segment Device Driver uninstalled\n");
+
+    return;
 }
 
+
 #ifdef MODULE
 module_init(xlseg_init);
 module_exit(xlseg_cleanup);
diff --git a/xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/block/xl_segment_proc.c b/xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/block/xl_segment_proc.c
new file mode 100644 (file)
index 0000000..8525d78
--- /dev/null
@@ -0,0 +1,280 @@
+/*
+ * xl_segment_proc.c
+ * 
+ * XenoLinux virtual disk proc interface .
+ */
+
+
+#include <linux/config.h>
+#include <linux/module.h>
+
+#include <linux/proc_fs.h>
+#include <linux/delay.h>
+#include <asm/uaccess.h>
+#include <asm/atomic.h>
+
+#include <asm/hypervisor-ifs/block.h>
+#include <asm/hypervisor-ifs/hypervisor-if.h>
+
+static struct proc_dir_entry *vhd;
+xv_disk_t xvd;
+
+extern atomic_t xlblk_control_count;                           /* xl_block.c */
+
+int hypervisor_request(void *          id,
+                       int             operation,
+                       char *          buffer,
+                       unsigned long   block_number,
+                       unsigned short  block_size,
+                       kdev_t          device,
+                      struct gendisk *gd);
+
+/******************************************************************/
+
+static int proc_read_vhd(char *page, char **start, off_t off,
+                        int count, int *eof, void *data)
+{
+  return 0;
+}
+
+#define isdelim(c) \
+  (c==' '||c==','||c=='\n'||c=='\r'||c=='\t'||c==':'||c=='('||c==')' ? 1 : 0)
+
+char *get_string(char *string)                          /* a bit like strtok */
+{
+  static char *temp;
+  int loop = 0;
+
+  if (string != NULL)  
+    temp = string;
+  else
+    string = temp;
+
+ try_again:
+
+  while (!isdelim(string[loop]))
+  {
+    if (string[loop] == '\0')
+      return NULL;
+    loop++;
+  }
+
+  string[loop] = '\0'; 
+  temp = (string + loop + 1);
+
+  if (loop == 0)
+  {
+    string = temp;
+    goto try_again;
+  }
+
+  return string;
+}
+
+
+#define isdigit(c) (c >= '0' && c <= '9' ? 1 : 0)
+unsigned long to_number(char *string)                                /* atoi */
+{
+  unsigned long value = 0;
+
+  if (string == NULL) return 0;
+
+  while (!isdigit(*string) && *string != '\0') string++;
+
+  while (isdigit(*string))
+  {
+    value = value * 10 + (*string - '0');
+    string++;
+  }
+
+  return value;
+}
+
+static int proc_write_vhd(struct file *file, const char *buffer,
+                         unsigned long count, void *data)
+{
+  char *local = kmalloc((count + 1) * sizeof(char), GFP_KERNEL);
+  char *string;
+  int loop;
+  int counter;
+  xv_disk_t xvd;
+
+  memset (&xvd, 0, sizeof(xvd));
+
+  if (copy_from_user(local, buffer, count))
+  {
+    return -EFAULT;
+  }
+  local[count] = '\0';
+
+  string = get_string(local);                             /* look for Domain */
+  if (string == NULL)                                        /* empty string */
+  {
+    return count;
+  }
+  if (*string != 'd' && *string != 'D')
+  {
+    printk (KERN_ALERT 
+           "error: domain specifier missing [%s]. should be \"domain\".\n",
+           string);
+    return count;
+  }
+
+  string = get_string(NULL);                                /* domain number */
+  if (string == NULL)
+  {
+    printk (KERN_ALERT "error: domain number missing\n");
+    return count;
+  }
+  xvd.domain = (int) to_number(string);
+
+  string = get_string(NULL);
+  if (string && (strcmp(string, "RO") == 0 || strcmp(string, "ro") == 0))
+  {
+    xvd.mode = XEN_DISK_READ_ONLY;
+  }
+  else if (string && (strcmp(string, "RW") == 0 || strcmp(string, "rw") == 0))
+  {
+    xvd.mode = XEN_DISK_READ_WRITE;
+  }
+  else
+  {
+    printk (KERN_ALERT 
+           "error: bad mode [%s]. should be \"rw\" or \"ro\".\n",
+           string);
+    return count;
+  }
+
+  string = get_string(NULL);                             /* look for Segment */
+  if (string == NULL || (*string != 's' && *string != 'S'))
+  {
+    printk (KERN_ALERT 
+           "error: segment specifier missing [%s]. should be \"segment\".\n",
+           string);
+    return count;
+  }
+
+  string = get_string(NULL);                               /* segment number */
+  if (string == NULL)
+  {
+    printk (KERN_ALERT "error: segment number missing\n");
+    return count;
+  }
+  xvd.segment = (int) to_number(string);
+
+  string = get_string(NULL);                             /* look for Extents */
+  if (string == NULL || (*string != 'e' && *string != 'E'))
+  {
+    printk (KERN_ALERT 
+           "error: extents specifier missing [%s]. should be \"extents\".\n",
+           string);
+    return count;
+  }
+
+  string = get_string(NULL);                            /* number of extents */
+  if (string == NULL)
+  {
+    printk (KERN_ALERT "error: number of extents missing\n");
+    return count;
+  }
+  xvd.ext_count = (int) to_number(string);
+
+  /* ignore parenthesis */
+
+  for (loop = 0; loop < xvd.ext_count; loop++)
+  {
+    string = get_string(NULL);                              /* look for Disk */
+    if (string == NULL || (*string != 'd' && *string != 'D'))
+    {
+      printk (KERN_ALERT 
+             "hmm, extent disk specifier missing [%s]. should be \"disk\".\n",
+             string);
+      return count;
+    }
+    string = get_string(NULL);                                /* disk number */
+    if (string == NULL)
+    {
+      printk (KERN_ALERT "error: disk number missing\n");
+      return count;
+    }
+    xvd.extents[loop].disk = (int) to_number(string);
+
+    string = get_string(NULL);                            /* look for Offset */
+    if (string == NULL || (*string != 'o' && *string != 'O'))
+    {
+      printk (KERN_ALERT 
+             "error: disk offset missing [%s]. should be \"offset\".\n",
+           string);
+      return count;
+    }
+    string = get_string(NULL);                                     /* offset */
+    if (string == NULL)
+    {
+      printk (KERN_ALERT "error: offset missing\n");
+      return count;
+    }
+    xvd.extents[loop].offset =  to_number(string);
+
+    string = get_string(NULL);                              /* look for Size */
+    if (string == NULL || (*string != 's' && *string != 'S'))
+    {
+      printk (KERN_ALERT 
+             "error: extent size missing [%s]. should be \"size\".\n",
+           string);
+      return count;
+    }
+    string = get_string(NULL);                                       /* size */
+    if (string == NULL)
+    {
+      printk (KERN_ALERT "error: extent size missing\n");
+      return count;
+    }
+    xvd.extents[loop].size =  to_number(string);
+  }
+
+  {
+    /* get lock xlblk_control_lock     */
+    counter = atomic_read(&xlblk_control_count);
+    atomic_inc(&xlblk_control_count);
+    /* release lock xlblk_control_lock */
+  }
+  if (hypervisor_request (NULL, XEN_BLOCK_SEG_CREATE, (char *)&xvd,
+                         0, 0, (kdev_t) 0,
+                         (struct gendisk *)NULL))
+    BUG();
+  HYPERVISOR_block_io_op();
+
+  while (atomic_read(&xlblk_control_count) != counter) barrier();
+
+  return count;
+}
+
+/******************************************************************/
+
+int __init xlseg_proc_init(void)
+{
+  vhd = create_proc_entry("xeno/dom0/vhd", 0644, NULL);
+  if (vhd == NULL)
+  {
+    panic ("xlseg_init: unable to create vhd proc entry\n");
+  }
+  vhd->data       = NULL;
+  vhd->read_proc  = proc_read_vhd;
+  vhd->write_proc = proc_write_vhd;
+  vhd->owner      = THIS_MODULE;
+
+  memset(&xvd, 0, sizeof(xvd));
+
+  printk(KERN_ALERT "XenoLinux Virtual Disk Device Monitor installed\n");
+  return 0;
+}
+
+static void __exit xlseg_proc_cleanup(void)
+{
+  printk(KERN_ALERT "XenoLinux Virtual Disk Device Monitor uninstalled\n");
+}
+
+#ifdef MODULE
+module_init(xlseg_proc_init);
+module_exit(xlseg_proc_cleanup);
+#endif
index 470b2067264112d7a92898ec063fd5f8721cd235..842dd069f1e064eeb0146d6190176d9dd92676d3 100644 (file)
@@ -1505,6 +1505,7 @@ int __init blk_dev_init(void)
 #ifdef CONFIG_XENOLINUX_BLOCK
     xlblk_init();
     xlseg_init();
+    xlseg_proc_init();
 #endif
 
        return 0;
index 0be65ab99daaf57b37c1db09a32885fd013679f4..e7fa20195568e226c7ac20471ed8ff26f868c380 100644 (file)
@@ -328,6 +328,13 @@ static void floppy_off(unsigned int nr);
 /* #define DEVICE_INTR */
 #define DEVICE_NR(device) (MINOR(device))
 
+#elif (MAJOR_NR == XLSEG_MAJOR)
+
+#define DEVICE_NAME "xeno segment"
+#define DEVICE_REQUEST do_xlseg_request
+/* #define DEVICE_INTR */
+#define DEVICE_NR(device) (MINOR(device))
+
 #endif /* MAJOR_NR == whatever */
 
 /* provide DEVICE_xxx defaults, if not explicitly defined
index dfcb6f79f0ae73fa794cc49b6c5ca9cb6f2bd8a5..9cac1c28810f79f9f1c87ac572f17b30c7415301 100644 (file)
 
 #define        UMEM_MAJOR      116     /* http://www.umem.com/ Battery Backed RAM */
 
-#define XLBLK_MAJOR    123     /* XenoLinux Block Device */
+/* note: 123, 124, 125, 126 and 234, 235, 236, 237 are defined in xeno_major */
+#include <asm/hypervisor-ifs/xeno-major.h>
 
 #define RTF_MAJOR      150
 #define RAW_MAJOR      162
index b0b143a264c7872fad0caa1de7f65114b2edced9..ddf2f96a39e0a92f6e1bd5af2e23fb5907e0e627 100644 (file)
@@ -235,6 +235,10 @@ static struct dev_name_struct {
         { "xhdb",    0x7C00 },
         { "xhdc",    0x7D00 },
         { "xhdd",    0x7E00 },
+        { "vhda",    0xEA00 },
+        { "vhdb",    0xEB00 },
+        { "vhdc",    0xEC00 },
+        { "vhdd",    0xED00 },
 #endif
        { "nftla", 0x5d00 },
        { "nftlb", 0x5d10 },